package yz.com.javautil.utilpackage;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;
import org.springframework.cglib.core.Converter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 使用 cglib 转换对象
 * 注意：对象避免使用Lombok的@Accessors注解，否则将无法复制。
 *
 * @author yuanzheng
 */
@Slf4j
public class FastCopyUtils_ {

    private static Map<String, BeanCopier> BEAN_COPIER_CACHE_MAP = new HashMap<>();

    /**
     * 将列表内的对象转换成指定类对象（列表对象转换）
     *
     * @param fromList 要转换的对象列表
     * @param toClass  转换后的对象类
     * @return 转换后的list
     */
    public static <F, T> List<T> listCopy(List<F> fromList, Class<T> toClass) {
        List<T> toList = new ArrayList<>(fromList.size());
        fromList.forEach(v -> {
            toList.add(copy(v, toClass));
        });
        return toList;
    }

    /**
     * 将对象转换成指定类型的对象（单个对象转换）
     *
     * @param fromObject 待转换对象
     * @param toClass    转换后的对象类
     * @return 转换成的类对象
     */
    public static <T> T copy(Object fromObject, Class<T> toClass) {
        T targetEntity = null;
        try {
            targetEntity = toClass.newInstance();
        } catch (Exception e) {
            log.error("创建对象发生异常: ", e);
        }
        return copy(fromObject, toClass, targetEntity, null);
    }

    /**
     * 将对象转换成指定类型的对象（单个对象转换）
     *
     * @param fromObject   待转换对象
     * @param toClass      转换后的对象类
     * @param useConverter 是否使用转换器
     * @return 转换成的类对象
     */
    public static <T> T copy(Object fromObject, Class<T> toClass, boolean useConverter) {
        T targetEntity = null;
        try {
            targetEntity = toClass.newInstance();
        } catch (Exception e) {
            log.error("创建对象发生异常: ", e);
        }
        return copy(fromObject, toClass, targetEntity, null);
    }

    /**
     * 将对象转换成指定类型的对象
     *
     * @param fromObject   待转换对象
     * @param toClass      转换后的对象类
     * @param targetEntity 目标对象
     * @param useConverter 是否使用转换器
     * @return 转换成的类对象
     */
    private static <T> T copy(Object fromObject, Class<?> toClass, T targetEntity, Converter useConverter) {
        if (fromObject == null) {
            return targetEntity;
        }
        // 待转换的对象类
        final Class<?> formClass = fromObject.getClass();
        // 创建缓存建
        String cacheKey = buildCacheKey(formClass, toClass);
        // 缓存或获取双向 BeanCopier 并执行复制
        if (!BEAN_COPIER_CACHE_MAP.containsKey(cacheKey)) {
            addBothWayBeanCopy(formClass, toClass);
        }
        BEAN_COPIER_CACHE_MAP.get(cacheKey).copy(fromObject, targetEntity, useConverter);
        return targetEntity;
    }

    /**
     * 添加双向 BeanCopier（重载方法）
     *
     * @param fromClass 转换前的对象类
     * @param toClass   转换后的对象类
     */
    private static void addBothWayBeanCopy(Class<?> fromClass, Class<?> toClass) {
        addBothWayBeanCopy(fromClass, toClass, false);
    }

    /**
     * 添加双向 BeanCopier（重载方法）
     *
     * @param fromClass    转换前的对象类
     * @param toClass      转换后的对象类
     * @param useConverter 是否使用转换器
     */
    private static void addBothWayBeanCopy(Class<?> fromClass, Class<?> toClass, boolean useConverter) {
        BEAN_COPIER_CACHE_MAP.put(buildCacheKey(fromClass, toClass), BeanCopier.create(fromClass, toClass, useConverter));
        BEAN_COPIER_CACHE_MAP.put(buildCacheKey(toClass, fromClass), BeanCopier.create(toClass, fromClass, useConverter));
    }

    /**
     * 创建缓存建
     *
     * @param clz1 类1
     * @param clz2 类2
     * @return 缓存建
     */
    private static String buildCacheKey(Class<?> clz1, Class<?> clz2) {
        return clz1.getSimpleName() + "_" + clz2.getSimpleName();
    }

}
